/**
  ******************************************************************************
  * @file    TempControl_Driver.c
  * @author  tuancheng_Zero
  * @version V0.1
  * @date    01/15/2025
  * @brief   temperature control Driver
  ******************************************************************************
*/ 
#include <includes.h>
#include "TempControl_Driver.h"

// 局部宏定义
#define TempControl_DeviceAddr           0x0002      // 设备地址
#define TempControl_RgAddr_PV            0x0000      // 测量值地址
#define TempControl_RgAddr_SV            0x0002      // 设定值地址

// 局部变量
static uint8_t TempCtl_DataTxBuff[50] = {0};        // 温控器数据缓冲
static uint8_t * TempCtl_DataRxPoint = NULL;        // 温控器接收数据指针
static uint8_t waitBusTimeout = 0;                  // 等待总线超时
static uint16_t setTempValue = 0;                   // 设定的温度值

// 全局变量
TempContrlStatus_ST tempControlStatus_st = {0};     // 温控器状态结构体


/// @brief 数据处理函数
/// @param pData 数据缓冲
/// @return Always true
uint8_t TempCtl_RecvHandle(uint8_t * pData){
    // 释放RS485总线
    OSSemPost((OS_EVENT *)App_Sem_RS485BUSIDLE);
    waitBusTimeout = 0;
    // 通知数据接收完成
    TempCtl_DataRxPoint = pData;
    OSSemPost((OS_EVENT *)App_Sem_TEMPCTLRC);
    
    return DEF_TRUE;
}

/// @brief 数据传输
/// @param cmd 命令号
/// @param addr 寄存器地址
/// @param data 单个数据内容(cmd为03H时输入长度 cmd为06H时输入内容)
/// @return Always true
static uint8_t TempCtl_TransferData(uint8_t cmd, uint16_t addr, uint16_t data){
    uint8_t os_err;
    uint16_t crcValue = 0;

    // 等待RS485总线空闲
    OSSemPend((OS_EVENT *)App_Sem_RS485BUSIDLE, OS_TICKS_PER_SEC * 1, &os_err);// 1秒后超时
    if(os_err == OS_ERR_TIMEOUT)
        waitBusTimeout = 1;
    // 数据组织
    TempCtl_DataTxBuff[0] = TempControl_DeviceAddr;
    TempCtl_DataTxBuff[1] = cmd;
    TempCtl_DataTxBuff[2] = addr >> 8;
    TempCtl_DataTxBuff[3] = addr;
    TempCtl_DataTxBuff[4] = data >> 8;
    TempCtl_DataTxBuff[5] = data;
    // 计算校验和
    crcValue = Comm_CalCRC16(TempCtl_DataTxBuff, 6);
    TempCtl_DataTxBuff[6] = crcValue >> 8;
    TempCtl_DataTxBuff[7] = crcValue;
    // 往RS485发送数据
    RS485_DmaTransferData(TempCtl_DataTxBuff, 8);

    return DEF_TRUE;
}

/// @brief 写单个寄存器数据0x06
/// @param addr 寄存器地址
/// @param data 数据
/// @return 0失败  1成功
static uint8_t TempCtl_WriteSingleRegister(uint16_t addr, uint16_t data){
    uint8_t os_err = 0;

    // 发送数据
    if(TempCtl_TransferData(0x06, addr, data) != DEF_TRUE)
        return DEF_FALSE;
    // 等待接收温控器响应(等1秒)
    OSSemPend((OS_EVENT *)App_Sem_TEMPCTLRC,OS_TICKS_PER_SEC / 2,&os_err);
    if(os_err == OS_ERR_TIMEOUT)
        return DEF_FALSE;
    // 判断接收内容是否与发送内容一致
    if(memcmp(TempCtl_DataTxBuff, TempCtl_DataRxPoint, 8) == 0)
        return DEF_TRUE;
    return DEF_FALSE;
}

/// @brief 获取温控器状态值
/// @param  none
/// @return 0失败  1成功
uint8_t TempCtl_QueryStatus(void){
    uint8_t os_err = 0;
    // 发送数据
    if(TempCtl_TransferData(0x03, TempControl_RgAddr_PV, 0x03) != 1)
        return DEF_FALSE;
    // 等待接收温控器响应(等0.5秒)
    OSSemPend((OS_EVENT *)App_Sem_TEMPCTLRC,OS_TICKS_PER_SEC / 2,&os_err);
    if(os_err == OS_ERR_TIMEOUT)
        return DEF_FALSE;
    // 匹配命令号
    if(TempCtl_DataRxPoint[1] != 0x03)
        return DEF_FALSE;
    // 获取状态数据
    tempControlStatus_st.PV  = (TempCtl_DataRxPoint[3] << 8) | TempCtl_DataRxPoint[4];
    tempControlStatus_st.LED = (TempCtl_DataRxPoint[5] << 8) | TempCtl_DataRxPoint[6];;
    tempControlStatus_st.SV  = (TempCtl_DataRxPoint[7] << 8) | TempCtl_DataRxPoint[8];;
    return DEF_TRUE;
}

/// @brief 设定温控器温度值
/// @param  tempValue 温度值(倍率0.1)
/// @return 0失败  1成功
static uint8_t TempCtl_SetTemperature(uint16_t tempValue){
    // 发送数据
    if(TempCtl_WriteSingleRegister(TempControl_RgAddr_SV, tempValue) == 0)
        return DEF_FALSE;
    // 查询温控器状态
    if(TempCtl_QueryStatus() != DEF_TRUE)
        return DEF_FALSE;
    if(tempControlStatus_st.SV == tempValue)
        return DEF_TRUE;
    return DEF_FALSE;
}

/// @brief 设定温控器温度值(外部调用)
/// @param tempValue 温度值(倍率0.1)
/// @return Always True
uint8_t TempCtl_SetTemperatureEx(uint16_t tempValue){
    setTempValue = tempValue;
    SetOSFlagsForNewInform(App_Flags_RS485Handle,RS485HandleFlags_TempCtlOperate);
    return DEF_TRUE;
}

/// @brief 温控器处理函数
/// @param  noen
uint8_t TempCtl_FuncOperate(void){
    return TempCtl_SetTemperature(setTempValue);
}